<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
#
# Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
abstract class DMModel {

	private $objects = array();

	/**
	 * Associates the instance with the supplied object (<code>$obj</code>).
	 * That object will gain all of the methods and properties of this instance
	 * via PHP magic methods.
	 *
	 * @param object obj
	 * @throws DMIllegalArgumentException if <code>$obj</code> is not an object
	 */
	public final function addAssociatedModel($obj) {
		if (!is_object($obj)) {
			throw new DMIllegalArgumentException();
		}
		if (!in_array($obj, $this->objects)) {
			$this->objects[] = $obj;
		}
	}

	/**
	 * @return array Array of all model objects that have been associated with
	 * the instance.
	 */
	public final function getAssociatedModels() {
		return $this->objects;
	}

	/**
	 * Disassociates the supplied model object $obj from the instance.
	 *
	 * @param object obj
	 * @throws DMIllegalArgumentException if <code>$obj</code> is not an object
	 */
	public final function disassociateModel($obj) {
		if (!is_object($obj)) {
			throw new DMIllegalArgumentException();
		}
		for ($i = 0; $i < count($this->objects); $i++) {
			if ($this->objects[$i] === $obj) {
				unset($this->objects[$i]);
			}
		}
	}

	/**
	 * Not to be invoked publicly.
	 *
	 * @param string method
	 * @param array args
	 * @throws DMNoSuchMethodException
	 */
	public function __call($method, $args) {
		foreach ($this->objects as $obj) {
			if (method_exists($obj, $method)) {
				return call_user_func_array(array($obj, $method), $args);
			}
		}
		throw new DMNoSuchMethodException($method);
	}

	/**
	 * Not to be invoked publicly.
	 *
	 * @param string var
	 * @return
	 * @throws DMNoSuchFieldException
	 */
	public function __get($var) {
		if (property_exists($this, $var)) {
			return $this->$var;
		} else {
			foreach ($this->objects as $obj) {
				if (property_exists($obj, $var)) {
					return $obj->$var;
				}
			}
		}
		throw new DMNoSuchFieldException($var);
	}

	/**
	 * Not to be invoked publicly.
	 *
	 * @param string var
	 * @param mixed val
	 * @return void
	 * @throws DMNoSuchFieldException
	 */
	public function __set($var, $val) {
		$found = false;
		if (property_exists($this, $var)) {
			$found = true;
			$this->$var = $val;
		} else {
			foreach ($this->objects as $obj) {
				if (property_exists($obj, $var)) {
					$found = true;
					$obj->$var = $val;
				}
			}
		}
		if (!$found) {
			throw new DMNoSuchFieldException($var);
		}
	}

}